package fr.pud.client.view;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;

import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;

import fr.pud.client.i18n.LanguagesConstants;
import fr.pud.client.model.Address;
import fr.pud.utils.Conversion;
import fr.pud.utils.Tools;

/**
 * Apr 8, 2012 - Projet_Ose.
 * @author Simon Devineau, Adrien Hierry, Leopold Houdin, Pierre Reliquet
 *         Ecole des Mines de Nantes
 *         AddAddressesFromCSV.java
 *         This class allows to the user to load addresses from a csv file.
 *         The swing worker displays the progression of the reading.
 */
public class AddAddressesFromCSV extends
        SwingWorker<HashSet<HashSet<Address>>, String> {
    private File                csvFile;
    private ProgressFrameForCSV progressFrame;

    /**
     * This constructor create the frame where the information will be display
     * and
     * configure the way of how the information change.
     * @param f
     *            , the file which contains the addresses.
     */
    public AddAddressesFromCSV(File f) {
        this.csvFile = f;
        this.progressFrame = new ProgressFrameForCSV();
        this.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("progress".equals(evt.getPropertyName())) {
                    AddAddressesFromCSV.this.progressFrame.getMyProgressBar()
                            .setValue((Integer) evt.getNewValue());
                    AddAddressesFromCSV.this.progressFrame
                            .getMyProgressBar()
                            .setString(
                                    LanguagesConstants.LANGUAGE
                                            .getString(LanguagesConstants.PROGRESS)
                                            + ": " + evt.getNewValue() + "%");
                }
            }
        });
    }

    /**
     * This method read the file f and by means of Nominatim find all the
     * possibilities of addresses (corresponding to the string written by the
     * user).
     * @param f
     *            , the file to read.
     * @return an HashSet<HashSet<Address>> which represents all the
     *         possibilities for each address.
     */
    private HashSet<HashSet<Address>> addUserAddress(File f) {
        HashSet<HashSet<Address>> addressList = new HashSet<HashSet<Address>>();
        String[] array;
        String toRead;
        String completeAddress = "";
        int indexLines = 1;
        int semiColonNumber = 0;
        int percentage = 0;
        Scanner scan;
        try {
            scan = new Scanner(f);
            long size = f.length();
            while (scan.hasNextLine()) {
                toRead = scan.nextLine();
                if (!toRead.equals("")) {
                    toRead = toRead.replace(";;", "; ;");
                    if (indexLines == 1) {
                        String firstLine = toRead;
                        while (firstLine.contains(";")) {
                            firstLine = firstLine.substring(firstLine
                                    .indexOf(";") + 1);
                            semiColonNumber++;
                        }
                        if (semiColonNumber == 0) {
                            semiColonNumber++;
                        }
                    }
                    percentage += toRead.length();
                    array = toRead.split(";");
                    int arrayLength = array.length;
                    // If the number of semi columns is not valid, the program
// is
                    // closed
                    if (arrayLength != semiColonNumber) {
                        Tools.writeToLogFile(
                                LanguagesConstants.LANGUAGE
                                        .getString(LanguagesConstants.BAD_CSV_FILE)
                                        + " " + indexLines, true);
                        break;
                    }
                    // Get the line
                    int indexArray = 0;
                    while (indexArray < semiColonNumber) {
                        completeAddress = completeAddress + ", "
                                + array[indexArray];
                        if (indexArray == 0) {
                            completeAddress = completeAddress
                                    .substring(completeAddress.indexOf(",") + 1);
                        }
                        indexArray++;
                    }
                    HashSet<Address> arrayList = Conversion
                            .geocoding(completeAddress);
                    if (arrayList != Conversion.GEOCODING_ERROR) {
                        addressList.add(arrayList);
                    }
                    // Transmit the value of the progress
                    this.setProgress((int) (percentage * 100 / size));
                    indexLines++;
                    // Publish the address read
                    this.publish(LanguagesConstants.LANGUAGE
                            .getString(LanguagesConstants.ADDRESS_LECTURE)
                            + completeAddress);
                    completeAddress = "";
                }
            }
        }
        catch (Exception e) {
            Tools.writeToLogFile(
                    LanguagesConstants.LANGUAGE
                            .getString(LanguagesConstants.FILE)
                            + LanguagesConstants.LANGUAGE
                                    .getString(LanguagesConstants.ERROR_FILE),
                    true, e.getStackTrace());
        }
        return addressList;
    }

    /**
     * Launch in background the reading of the file.
     */
    @Override
    protected HashSet<HashSet<Address>> doInBackground() throws Exception {
        return this.addUserAddress(this.getCsvFile());
    }

    /**
     * This method displays all the possibilities of each address input by the
     * user and ask him to make a choice between them.
     */
    @Override
    protected void done() {
        try {
            /* Le traitement est terminé. */
            this.setProgress(100);
            /*
             * À la fin du traitement, affichage du nombre de fichiers parcourus
             * dans le textfield.
             */
            this.getProgressFrame().dispose();
            @SuppressWarnings("unused")
            AddressSuggestionsFrame suggestionsFrame = new AddressSuggestionsFrame(
                    this.get());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @return the csv file to read.
     */
    public File getCsvFile() {
        return this.csvFile;
    }

    /**
     * @return the JPRogressBar which display the progression of the file
     *         lecture.
     */
    public JProgressBar getProgressBar() {
        return this.progressFrame.getMyProgressBar();
    }

    /**
     * @return the progressFrame
     */
    public ProgressFrameForCSV getProgressFrame() {
        return this.progressFrame;
    }

    public JTextArea getTextArea() {
        return this.progressFrame.getTextArea();
    }

    /**
     * Display the line which is reading by the swing worker.
     */
    @Override
    protected void process(List<String> strings) {
        for (String s : strings) {
            this.getTextArea().append(s + '\n');
        }
    }
}
